

"""
"""

import timer
from weakref import WeakValueDictionary
from utils import Identified
from fal.event import EventManager

class PollRunningError(Exception):
    """ Poll is already running """

class Poll(Identified):
    """
    Handles polling logic (specifically server-side).
    
    This is glue between rules and the server/FAL.
    
    This is used similar to querying message boxes. It is assumed that a client 
    can show multiple polls at once and that a client may change their mind 
    until the poll closes.
    """
    game = None
    prompt = None
    responses = None
    playersResponded = None
    running = False
    playerResponses = None
    
    def __init__(self, game, prompt, responses):
        super(Poll, self).__init__(self)
        self.game = game
        self.prompt = prompt
        self.responses = responses
        self.running = False
        self.playerResponses = {}
        
    def poll(self):
        """ Run the poll """
        if self.running: raise PollRunningError, "This poll is already running" 
        self.running = True
        self.playersResponded = set()
        EventManager.registerCallback('game.players.add', self.addPlayer)
        EventManager.registerCallback('game.players.del', self.delPlayer)
        for player in self.game.players:
            self.addPlayer(player)
    
    EventManager.registerEvent('poll.finish')
    def stop(self):
        """ Stop the poll """
        if not self.running: return
        self.running = False
        EventManager.unregisterCallback('game.players.add', self.addPlayer)
        EventManager.unregisterCallback('game.players.del', self.delPlayer)
        EventManager.triggerEvent('poll.finish', self, self.playerResponses)
        for player in self.game.players:
            #TODO: Send network activity: 
            #    Tell all the players the poll stopped.
            pass
    
    EventManager.registerEvent('poll.response')
    def playerResponse(self, player, response):
        """ Callback for handling network input """
        self.playersResponded.add(player)
        if response not in self.repsonses:
            #TODO:Network: Send client an error
            return
        self.playerResponses[player] = response
        EventManager.triggerEvent('poll.response', self, player, response)
    
    @classmethod
    def networkInput(cls, id, player, response):
        """ Handles looking up a poll and telling it a response. """
        poll = cls.GetObject(id)
        poll.playerResponse(player, response)
    
    def addPlayer(self, player):
        """ Tell new player of poll """
        #TODO: Network Code: Send poll to player
        pass
    
    def delPlayer(self, player):
        """ Removes a player from this poll """
        # Don't tell the client to remove the poll, they do that on their own
        try: self.playersResponded.remove(player)
        except KeyError: pass
        try: del self.playerResponses[player]
        except KeyError: pass
    
    def __del__(self):
        self.stop()
        

class SimplePoll(Poll):
    """
    Simple Polls run until all players have voted.
    """
    
    def playerResponse(self, player, response):
        super(SimplePoll, self).playerResponse(player, response)
        if len(self.playersResponded) >= len(self.game.players):
            EventManager.triggerEvent('poll.finish', self, self.playerResponses)


class TimedPoll(Poll):
    """
    A poll that lasts n seconds.
    """
    
    timer = None
    
    def __init__(self, game, prompt, responses, time=30.0):
        super(TimedPoll, self).__init__(self, game, prompt, responses)
        self.timer = timer.Timer(time, self.stop)
        self.timer.start()
        
    
class IdleTimeoutPoll(Poll):
    """
    A poll that runs until players stop voting for n seconds
    """
    
    timer = None
    
    def __init__(self, game, prompt, responses, time=30.0):
        super(IdleTimeoutPoll, self).__init__(self, game, prompt, responses)
        self.timer = timer.Timer(time, self.stop)
        self.timer.start()
        
    def playerResponse(self, player, response):
        self.timer.cancel()
        super(IdleTimeoutTimer, self).playerResponse(self, player, response)
        self.timer.start()